#pragma once
#include "Comm.hpp"
#include "Reactor.hpp"
#include "Util.hpp"
#define ONCE_SIZE 128
// 基本IO模块
//  1: 成功读取
//  0: 对端链接断开
// -1: 读取出错
int RecvCore(std::string &inbuffer, const int &sock)
{
    while (true)
    {
        char buffer[ONCE_SIZE];
        ssize_t s = recv(sock, buffer, ONCE_SIZE - 1, 0);
        if (s > 0)
        {
            buffer[s] = '\0';
            inbuffer += buffer;
        }
        else if (s == 0)
        {
            return 0;
        }
        else
        {
            // IO被信号打断，概率特别低
            if (errno == EINTR)
                continue;
            // 1. 读完，底层没数据了
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                return 1;
            }
            // 2. 读取出错
            return -1;
        }
    }
}

int Recver(Event *pev)
{
    std::cout << "新链接的文件描述符fd[" << pev->_sock << "]读就绪" << std::endl;
    // 1. 真正的读取 ———— 采用的ET模式, sock获取到就绪时, epoll_wait只会通知一次, 需要一次性将数据读取完毕
    ssize_t result = RecvCore(pev->_inbuffer, pev->_sock);
    if (result <= 0)
    {
        if (pev->_errorer)
        {
            pev->_errorer(pev);
        }
        return -1;
    }
    // 2. 切分报文 ———— 获取的数据可能同时含有一个或多个报文
    // 1+2X2+3X3+4X
    std::vector<std::string> tokens;
    std::string sep = "X";
    SplitSegment(pev->_inbuffer, &tokens, sep);
    // 3. 反序列化报文 ———— 提取出每个有效报文进行业务处理
    for (auto &seg : tokens)
    {
        std::string data_x, data_y;
        if (Deserialize(seg, &data_x, &data_y))
        {
            // 4. 业务逻辑 ———— 获得结果
            int x = std::stoi(data_x);
            int y = std::stoi(data_y);
            int z = x + y;
            // 5. 构建响应 ———— 序列化1+2=3X2+3=5X3+4=7X
            std::string out;
            out += data_x;
            out += "+";
            out += data_y;
            out += "=";
            out += std::to_string(z);
            out += sep;

            pev->_outbuffer += out;
        }
    }
    // 6. 发送响应
    // 由于发送缓冲区通常都是有空间的, 因此只要发送缓冲区有数据, 写事件就绪
    // 因此只需要将报文处理之后放到发送缓冲区之后, 可以发送
    // 对应写事件通常都是有数据就就绪, 但是对于用户, 用户并不一定就绪
    // 因此写事件都是等发送缓冲区有数据之后再设置
    if (!(pev->_outbuffer).empty())
        pev->_R->EnableRW(pev->_sock, true, true);

    return 0;
}

//  1: 全部将数据发送完成
//  0: 数据没有发完，但是不能再发了
// -1: 发送失败
int SendCore(int sock, std::string &outbuffer)
{
    while (true)
    {
        // 累计发送的字节数
        int total = 0;
        int size = outbuffer.size();
        const char *start = outbuffer.c_str();
        ssize_t curr_send = send(sock, start + total, size - total, 0);
        if (curr_send > 0)
        {
            total += curr_send;
            if (total == size)
            {
                outbuffer.clear();
                return 1;
            }
        }
        else
        {
            if (errno == EINTR)
            {
                continue;
            }
            else if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                outbuffer.erase(0, total);
                return 0;
            }
            return -1;
        }
    }
}

int Sender(Event *pev)
{
    std::cout << "Sender has been called" << std::endl;
    int result = SendCore(pev->_sock, pev->_outbuffer);
    if (result == 1)
    {
        pev->_R->EnableRW(pev->_sock, true, false); //按需设置
    }
    else if (result == 0)
    {
        pev->_R->EnableRW(pev->_sock, true, true); //按需设置
    }
    else
    {
        if (pev->_errorer)
            pev->_errorer(pev);
    }
}

int Errorer(Event *pev)
{
    std::cout << "Errorer been called" << std::endl;
    pev->_R->DeleteEvent(pev);
}